#include <iostream>
#include <string>
#include <vector>
#include "teacher.hpp"
#include "student.hpp"
#include "appointment.hpp"
#include <map>
#include <algorithm>
#include <fstream>


using namespace std;

class management_system {
private:
	vector<Student> students;
	vector<Teacher> teachers;
	vector<appointment> appointments;
	int chart_order;

bool checkFail() {
        if (std::cin.fail()) {
            std::cin.clear(); // 清除错误状态
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 丢弃无效输入
            //std::cout << "Invalid input. Please try again." << std::endl;
            return true;
        }
        return false;
    }

	void stop_func(){
		system("pause");
		system("cls");
	}

	void print_load(){	
		cout << "--------------------" << endl;
		cout << "|     1,student     |" << endl;
		cout << "|     2,teacher     |" << endl;
		cout << "|     3,manager     |" << endl;
		cout << "|     0,exit        |" << endl;
		cout << "--------------------" << endl;
	}
	void print_student_menu(){
		cout << "--------------------------------" << endl;
		cout << "|     1,reserve a computer room |" << endl;
		cout << "|     2,cancel a reservation    |" << endl;
		cout << "|     3,view my reservations    |" << endl;
		cout << "|     4,view all reservations   |" << endl;
		cout << "|     0,exit	                 |" << endl;
		cout << "--------------------------------" << endl;
	}
	void print_teacher_menu(){
		cout << "--------------------------------" << endl;
		cout << "|     1,view all reservations   |" << endl;
		cout << "|     2,approval appointment    |" << endl;
		cout << "|     0,exit	                 |" << endl;
		cout << "--------------------------------" << endl;
	}
	void print_manager_menu(){
		cout << "--------------------------------" << endl;
		cout << "|     1,add account             |" << endl;
		cout << "|     2,view account            |" << endl;
		cout << "|     3,view all room data      |" << endl;
		cout << "|     4,clear reservation       |" << endl;
		cout << "|     0,exit	                 |" << endl;
		cout << "--------------------------------" << endl;
	}
	
	int load_choice(){

		int choice;
		string password;
		string name;

		cout << "Enter your choice: " << endl;
		cin >> choice;
		if(checkFail())
		{
			return -1;
		}

		switch(choice){
			case 1:
				cout << "please enter your student name: " << endl;
				cin >> name;
				cout << "please enter your student password: " << endl;
				cin >> password;

				for(int i=0;i<students.size();i++){
					if(students[i].getName() == name && students[i].getpassword() == password){
						chart_order = i;
						return 1;
					}
				}
				cout << "Invalid name or password" << endl;
				break;
			case 2:
				cout << "please enter your teacher name: " << endl;
				cin >> name;
				cout << "please enter your teacher password: " << endl;
				cin >> password;

				for(int i=0;i<teachers.size();i++){
					if(teachers[i].getName() == name && teachers[i].getpassword() == password){
						chart_order = i;
						return 2;
					}
				}
				cout << "Invalid name or password" << endl;
				break;
			case 3:
				cout << "please enter your manager name: " << endl;
				cin >> name;
				cout << "please enter your manager password: " << endl;
				cin >> password;

				if(name == "admin" && password == "12345"){
					return 3;
				}
				cout << "Invalid name or password" << endl;
				break;
			case 0:
				cout << "Exiting..." << endl;
				return 0;
			default:
				cout << "Invalid choice" << endl;
				break;
		}
		return -1;
	}
	void student_function()
	{
		int choice;
		int choice_second_size;
		int choice_second_time;
		int size;
		int time;
		bool flag = true;

		while (1)
		{
		flag = true;
			

		print_student_menu();
		cout << "Enter your choice: " << endl;
		cin >> choice;
		if(checkFail())
		{
			choice = -1;
		}
		switch (choice)
		{

		case 0:
			cout << "Exiting..." << endl;
			return;

			case 1:
			cout << "Enter your need for computer room size" << endl;
			cout << "1,twenty_room" << endl;
			cout << "2,fifty_room" << endl;
			cout << "3,hundred_room" << endl;
			cin >> size;
			if(checkFail())
		{
			flag = false;
		}
		if(size < 1 || size > 3)
		{
			flag = false;
		}
			cout << "Enter your reservation time from Monday.am to Friday.pm " << endl;
			cout << "1,Monday_am" << endl;
			cout << "2,Monday_pm" << endl;
			cout << "3,Tuesday_am" << endl;
			cout << "4,Tuesday_pm" << endl;
			cout << "5,Wednesday_am" << endl;
			cout << "6,Wednesday_pm" << endl;
			cout << "7,Thursday_am" << endl;
			cout << "8,Thursday_pm" << endl;
			cout << "9,Friday_am" << endl;
			cout << "10,Friday_pm" << endl;
			cin >> time;
			if(checkFail() )
		{
			flag = false;
		}
		if( time < 1 || time > 10)
		{
			flag = false;
		}
		
			for(int i=0;i<appointments.size();i++){
				if(appointments[i].get_room_type() == size-1 && appointments[i].get_time() == time-1 && (appointments[i]).get_status() ==pending  || appointments[i].get_status() == approved){
					cout << "You have already reserved a room for this time" << endl;
					flag = false;
					break;
				}
			}
			if(flag){
			appointments.push_back(appointment((room_status)(size-1), (appointment_time)(time-1),students[chart_order]));
			cout << "Reservation success" << endl;
			}
			else{
			cout << "Reservation failed" << endl;
			}
			break;
		case 2:
			cout << "Enter you need to cancel reservation time" << endl;
			cout << "1,Monday_am" << endl;
			cout << "2,Monday_pm" << endl;
			cout << "3,Tuesday_am" << endl;
			cout << "4,Tuesday_pm" << endl;
			cout << "5,Wednesday_am" << endl;
			cout << "6,Wednesday_pm" << endl;
			cout << "7,Thursday_am" << endl;
			cout << "8,Thursday_pm" << endl;
			cout << "9,Friday_am" << endl;
			cout << "10,Friday_pm" << endl;
			cin >> choice_second_time;
			cout << "Enter you need to cancel reservation room type" << endl;
			cout << "1,twenty_room" << endl;
			cout << "2,fifty_room" << endl;
			cout << "3,hundred_room" << endl;
			cin >> choice_second_size;
			for(int i=0;i<appointments.size();i++){
				if(appointments[i].get_room_type() == choice_second_size-1 && appointments[i].get_time() == choice_second_time-1 && appointments[i].get_student() == students[chart_order])
				{
				appointments[i].set_status(canceled);
				}
			}
			break;
		case 3:
			for(int i=0;i<appointments.size();i++){
				if(appointments[i].get_student() == students[chart_order])
				{
					appointments[i].print_appointment();
				}
			}
			cout << "display over" << endl;
			break;
		case 4:
			for(int i=0;i<appointments.size();i++){
				appointments[i].print_appointment();
			}
			cout << "display over" << endl;
			break;
		default:
			cout << "Invalid choice" << endl;
			break;
		}
		stop_func();
		}
		
	}
	void teacher_function(){
		int choice;
		int choice_second_size;
		int choice_second_time;
		int temp;
		bool flag = false;

		while(1)
		{
			flag = false;
			print_teacher_menu();
			cout << "Enter your choice: " << endl;
			cin >> choice;
			if (checkFail())
			{
				choice = -1;
		}
		switch(choice)
		{
			case 0:
			cout << "Exiting..." << endl;
			return;
			case 1:
			for(int i=0;i<appointments.size();i++){
				appointments[i].print_appointment();
			}
				cout << "display over" << endl;
				break;
			case 2:
				cout << "Enter you need to cancel reservation room type" << endl;
			cout << "1,twenty_room" << endl;
			cout << "2,fifty_room" << endl;
			cout << "3,hundred_room" << endl;
			cin >> choice_second_size;
			if(checkFail() || choice_second_size < 1 || choice_second_size > 3)
			{
				cout << "error input" << endl;
				stop_func();
				continue;
			}

				cout << "Enter you need to cancel reservation time" << endl;
			cout << "1,Monday_am" << endl;
			cout << "2,Monday_pm" << endl;
			cout << "3,Tuesday_am" << endl;
			cout << "4,Tuesday_pm" << endl;
			cout << "5,Wednesday_am" << endl;
			cout << "6,Wednesday_pm" << endl;
			cout << "7,Thursday_am" << endl;
			cout << "8,Thursday_pm" << endl;
			cout << "9,Friday_am" << endl;
			cout << "10,Friday_pm" << endl;
			cin >> choice_second_time;
			if(checkFail() || choice_second_time < 1 || choice_second_time > 10)
			{
				cout << "error input" << endl;
				stop_func();
				continue;
			}
			for(int i=0;i<appointments.size();i++){
				if(appointments[i].get_room_type() == choice_second_size-1 && appointments[i].get_time() == choice_second_time-1 && appointments[i].get_status() == pending)
				{
					cout << "1,approved" << endl;
					cout << "2,rejected" << endl;
					cout << "Enter your choice: " << endl;
					cin >> temp;
					if(checkFail())
					{
						temp = -1;
					}
					switch (temp)
					{
					case 1:
						appointments[i].set_status(approved);
						flag = true;
						break;
					case 2:
						appointments[i].set_status(rejected);
						flag = true;
						break;
					default:
						cout << "Invalid choice" << endl;
						break;
					}
				}
				if(flag)
				{
					break;
				}

			}
				break;
			default:
				cout << "Invalid choice" << endl;
				break;
		}
	stop_func();
	}

	}
	void manager_function(){
		int choice;
		string type;
		string id;
		string password;
		string name;
		bool flag = true;

		while (1)
		{
			flag = true;
			print_manager_menu();
		
		
		cout << "Enter your choice: " << endl; 
		cin >> choice;
		if(checkFail())
		{
			choice = -1;
		}
		switch (choice)
		{
		case 1:
			cout << "Enter account type (student/teacher): " << endl;
			cin >> type;
			if(type == "student"){
			cout << "Enter student name: " << endl;
			cin >> name;
			cout << "Enter student password: " << endl;
			cin >> password;
			cout << "Enter student id: " << endl;
			cin >> id;


			for (int i = 0; i < students.size(); i++)
			{
				if (students[i].getid() == id || students[i].getName() == name)
				{
					cout << "Student account already exists" << endl;
					flag = false;
					break;
				}
			}
			if(flag)
			{
				students.push_back(Student(name, password, id));
				cout << "student account created successfully" << endl;
			}
			
			break;
			}
			else if(type == "teacher"){
			cout << "Enter teacher name: " << endl;
			cin >> name;
			cout << "Enter teacher password: " << endl;
			cin >> password;
			cout << "Enter teacher id: " << endl;
			cin >> id;
			
			for(int i=0;i<teachers.size();i++){
				if(teachers[i].getid() == id || teachers[i].getName() == name){
					cout << "Teacher account already exists" << endl;
					flag = false;
					break;
				}
			}
			if(flag)
			{
				teachers.push_back(Teacher(name, password, id));
				cout << "teacher account created successfully" << endl;
			}
			
			break;
			}
			else{
			cout << "Invalid account type" << endl;
			}
			break;

		case 2:
		if (students.empty() && teachers.empty())
		{
			cout << "No accounts found" << endl;
			break;
		
		}
		
			if(!students.empty())
			{
				for(int i=0;i<students.size();i++)
				{
					students[i].print();
				}
			}
			if(!teachers.empty())
			{
				for(int i=0;i<teachers.size();i++)
				{
					teachers[i].print();
				}
			}
			cout << "displaying all accounts" << endl;
			break;
		case 3:
			for(int i=0;i<appointments.size();i++){
				appointments[i].print_appointment();
			}
			cout << "display over" << endl;
			break;
		case 4:
			appointments.clear();
			cout << "All reservations cleared successfully" << endl;
			break;
		case 0:
			cout << "Exiting..." << endl;
			return;
		default:
			cout << "Invalid choice" << endl;
			break;
		}
		stop_func();
		}
	}

	void student_file_write()
	{
		ofstream outfile("students.txt", ios::binary);
		if(!outfile.is_open())
		{
			cout << "Error opening file" << endl;
			return;
		}

		size_t name_size;
		size_t password_size;
		size_t id_size;
		
		for(int i=0;i<students.size();i++)
		{
			name_size = students[i].getName().length();
			password_size = students[i].getpassword().length();
			id_size = students[i].getid().length();

			outfile.write(reinterpret_cast<char*>(&name_size), sizeof(size_t));
			outfile.write(students[i].getName().c_str(), name_size);
			outfile.write(reinterpret_cast<char*>(&password_size), sizeof(size_t));
			outfile.write(students[i].getpassword().c_str(), password_size);
			outfile.write(reinterpret_cast<char*>(&id_size), sizeof(size_t));
			outfile.write(students[i].getid().c_str(), id_size);
		}
		outfile.close();
	}
	void teacher_file_write()
	{
		ofstream outfile("teachers.txt", ios::binary);
		if(!outfile.is_open())
		{
			cout << "Error opening file" << endl;
			return;
		}

		size_t name_size;
		size_t password_size;
		size_t id_size;
		
		for(int i=0;i<teachers.size();i++)
		{
			name_size = teachers[i].getName().length();
			password_size = teachers[i].getpassword().length();
			id_size = teachers[i].getid().length();

			outfile.write(reinterpret_cast<char*>(&name_size), sizeof(size_t));
			outfile.write(teachers[i].getName().c_str(), name_size);
			outfile.write(reinterpret_cast<char*>(&password_size), sizeof(size_t));
			outfile.write(teachers[i].getpassword().c_str(), password_size);
			outfile.write(reinterpret_cast<char*>(&id_size), sizeof(size_t));
			outfile.write(teachers[i].getid().c_str(), id_size);
		}
		outfile.close();
	} 
	void appointment_file_write()
	{
		ofstream outfile("appointments.txt", ios::binary);
		if(!outfile.is_open())
		{
			cout << "Error opening file" << endl;
			return;
		}

		size_t name_size;
		size_t password_size;
		size_t id_size;



		for(int i=0;i<appointments.size();i++)
		{
			name_size = appointments[i].get_student().getName().length();
			password_size = appointments[i].get_student().getpassword().length();
			id_size = appointments[i].get_student().getid().length();

			outfile.write(reinterpret_cast<char*>(&name_size), sizeof(size_t));
			outfile.write(appointments[i].get_student().getName().c_str(), name_size);

			outfile.write(reinterpret_cast<char*>(&password_size), sizeof(size_t));
			outfile.write(appointments[i].get_student().getpassword().c_str(), password_size);
			
			outfile.write(reinterpret_cast<char*>(&id_size), sizeof(size_t));
			outfile.write(appointments[i].get_student().getid().c_str(), id_size);

			int room_type = appointments[i].get_room_type();
			outfile.write(reinterpret_cast<char*>(&room_type), sizeof(room_type));

			int status = appointments[i].get_status();
			outfile.write(reinterpret_cast<char*>(&status), sizeof(status));

			int time = appointments[i].get_time();
			outfile.write(reinterpret_cast<char*>(&time), sizeof(time));
		}
		outfile.close();
	} 

	void student_file_read(){
		ifstream infile("students.txt", ios::binary);
		if(!infile.is_open())
		{
			cout << "Error opening file" << endl;
			return;
		}


		size_t name_size;
		size_t password_size;
		size_t id_size;
		char* name_buffer;
		char* password_buffer;
		char* id_buffer;

	while (!infile.eof()) {
        infile.read(reinterpret_cast<char*>(&name_size), sizeof(name_size));
        if (infile.eof()) break;  
        name_buffer = new char[name_size + 1];  
        infile.read(name_buffer, name_size);
        name_buffer[name_size] = '\0'; 
        

		infile.read(reinterpret_cast<char*>(&password_size), sizeof(password_size));
        if (infile.eof()) break;  
        password_buffer = new char[password_size + 1];  
        infile.read(password_buffer, password_size);
        password_buffer[password_size] = '\0'; 
        

		infile.read(reinterpret_cast<char*>(&id_size), sizeof(id_size));
        if (infile.eof()) break;  
        id_buffer = new char[id_size + 1];  
        infile.read(id_buffer, id_size);
        id_buffer[id_size] = '\0'; 

		students.push_back(Student(name_buffer, password_buffer, id_buffer));

        delete[] id_buffer;  
		delete[] name_buffer;  
		delete[] password_buffer;  
    	}
	}
	void teacher_file_read(){

		ifstream infile("teachers.txt", ios::binary);
		if(!infile.is_open())
		{
			cout << "Error opening file" << endl;
			return;
		}

		size_t name_size;
		size_t password_size;
		size_t id_size;
		char* name_buffer;
		char* password_buffer;
		char* id_buffer;

		while (!infile.eof()) {
        infile.read(reinterpret_cast<char*>(&name_size), sizeof(name_size));
        if (infile.eof()) break;  
        name_buffer = new char[name_size + 1];  
        infile.read(name_buffer, name_size);
        name_buffer[name_size] = '\0'; 
        

		infile.read(reinterpret_cast<char*>(&password_size), sizeof(password_size));
        if (infile.eof()) break;  
        password_buffer = new char[password_size + 1];  
        infile.read(password_buffer, password_size);
        password_buffer[password_size] = '\0'; 
        

		infile.read(reinterpret_cast<char*>(&id_size), sizeof(id_size));
        if (infile.eof()) break;  
        id_buffer = new char[id_size + 1];  
        infile.read(id_buffer, id_size);
        id_buffer[id_size] = '\0'; 

		teachers.push_back(Teacher(name_buffer, password_buffer, id_buffer));

        delete[] id_buffer;  
		delete[] name_buffer;  
		delete[] password_buffer;  
    	}


	}
	void appointment_file_read(){
		ifstream infile("appointments.txt", ios::binary);
		if(!infile.is_open())
		{
			cout << "Error opening file" << endl;
			return;
		}


		size_t name_size;
		size_t password_size;
		size_t id_size;
		char* name_buffer;
		char* password_buffer;
		char* id_buffer;

		room_status room_type;
		appointment_status status;
		appointment_time room_time;

	while (!infile.eof()) {
        infile.read(reinterpret_cast<char*>(&name_size), sizeof(name_size));
        if (infile.eof()) break;  
        name_buffer = new char[name_size + 1];  
        infile.read(name_buffer, name_size);
        name_buffer[name_size] = '\0'; 
        

		infile.read(reinterpret_cast<char*>(&password_size), sizeof(password_size));
        if (infile.eof()) break;  
        password_buffer = new char[password_size + 1];  
        infile.read(password_buffer, password_size);
        password_buffer[password_size] = '\0'; 
        

		infile.read(reinterpret_cast<char*>(&id_size), sizeof(id_size));
        if (infile.eof()) break;  
        id_buffer = new char[id_size + 1];  
        infile.read(id_buffer, id_size);
        id_buffer[id_size] = '\0';

		infile.read(reinterpret_cast<char *>(&room_type), sizeof(room_type));
		infile.read(reinterpret_cast<char *>(&status), sizeof(status));
		infile.read(reinterpret_cast<char *>(&room_time), sizeof(room_time));

		appointments.push_back(appointment(Student(name_buffer, password_buffer, id_buffer), room_type, status, room_time));

        delete[] id_buffer;  
		delete[] name_buffer;  
		delete[] password_buffer;  
    	}
	}

public:
	void run(){
		while (1)
		{
			print_load();

			int choice = load_choice();

			if(choice == 1){
				system("cls");
				student_function();
				
			}
			else if(choice == 2){
				system("cls");
				teacher_function();


			}
			else if(choice == 3){
				system("cls");
				manager_function();
			}
			else if(choice == 0){
				break;
			}
			stop_func();
			
		}
		
	}
	
	management_system()
	{
		student_file_read();
		teacher_file_read();
		appointment_file_read();
	}

	~management_system()
	{
		student_file_write();
		teacher_file_write();
		appointment_file_write();
		

	}
};